package com.xu.cloud.auth.component.oauth;

import com.xu.cloud.auth.component.ThirdPartyComponent;
import com.xu.cloud.auth.enums.ThirdPartyEnum;
import com.xu.cloud.auth.exception.AuthErrorCodeEnum;
import com.xu.cloud.auth.pojo.bo.OAuth2AccessTokenBO;
import com.xu.cloud.auth.pojo.bo.OAuth2BO;
import com.xu.cloud.auth.pojo.bo.OAuth2GetAccessTokenReqBO;
import com.xu.cloud.auth.pojo.bo.OAuth2UserInfo;
import com.xu.cloud.auth.pojo.convert.OAuth2Converter;
import com.xu.cloud.auth.pojo.domain.CfgThirdPartyLoginDO;
import com.xu.cloud.common.util.AssertUtil;
import com.xu.cloud.common.util.JsonUtil;
import com.xu.cloud.common.util.RestTemplateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * oauth2 授权抽象类
 *
 * @author xuguan
 * @since 2025/2/28
 */
public abstract class AbsOAuth2 implements IOAuth2 {

    public static final Logger log = LoggerFactory.getLogger(AbsOAuth2.class);

    @Autowired
    protected ThirdPartyComponent thirdPartyComponent;
    @Autowired
    protected OAuth2Converter oAuth2Converter;

    /**
     * 支持的第三方应用类型
     */
    protected abstract ThirdPartyEnum supportThirdPartyEnum();

    /**
     * 获取三方access_token
     */
    protected OAuth2AccessTokenBO getAccessToken(String url, OAuth2GetAccessTokenReqBO getAccessTokenReqBo) {
        return RestTemplateUtil.doPost(url, JsonUtil.toJsonString(getAccessTokenReqBo), OAuth2AccessTokenBO.class);
    }

    /**
     * 获取三方用户手机号
     */
    protected String getThirdMobileNo(String url, OAuth2AccessTokenBO accessTokenBo) {
        return null;
    }

    /**
     * 获取三方用户邮箱
     */
    protected String getThirdEmail(String url, OAuth2AccessTokenBO accessTokenBo) {
        return null;
    }

    /**
     * 获取三方用户名
     */
    protected String getThirdUserName(String url, OAuth2AccessTokenBO accessTokenBo) {
        return null;
    }

    @Override
    public boolean support(ThirdPartyEnum thirdPartyEnum) {
        return Objects.equals(supportThirdPartyEnum(), thirdPartyEnum);
    }

    @Override
    public OAuth2AccessTokenBO getAccessToken(String code) {
        final ThirdPartyEnum thirdPartyEnum = supportThirdPartyEnum();
        final String thirdPartyType = thirdPartyEnum.getThirdPartyType();
        final String thirdPartyDesc = thirdPartyEnum.getThirdPartyDesc();
        log.info("{}{} oauth2 获取access_token开始, code={}", thirdPartyType, thirdPartyDesc, code);

        // oauth2授权请求获取access_token
        final OAuth2BO oAuth2Bo = queryOAuth2Bo(thirdPartyEnum);
        oAuth2Bo.setCode(code);
        final OAuth2GetAccessTokenReqBO getAccessTokenReqBo = oAuth2Converter.bo2ReqBo(oAuth2Bo);
        final OAuth2AccessTokenBO accessTokenBo = getAccessToken(oAuth2Bo.getThirdOauthUrl(), getAccessTokenReqBo);

        log.info("{}{} oauth2 获取access_token成功, accessTokenBo={}", thirdPartyType, thirdPartyDesc, accessTokenBo);
        return accessTokenBo;
    }

    @Override
    public OAuth2UserInfo oauth2UserInfo(OAuth2AccessTokenBO accessTokenBo) {
        final ThirdPartyEnum thirdPartyEnum = supportThirdPartyEnum();
        final String thirdPartyType = thirdPartyEnum.getThirdPartyType();
        final String thirdPartyDesc = thirdPartyEnum.getThirdPartyDesc();
        log.info("{}{} oauth2 获取三方应用用户信息开始, accessTokenBo={}", thirdPartyType, thirdPartyDesc, accessTokenBo);

        OAuth2UserInfo oAuth2UserInfo;
        final OAuth2BO oAuth2Bo = queryOAuth2Bo(thirdPartyEnum);
        final String thirdMobileNoUrl = oAuth2Bo.getThirdMobileNoUrl();
        final String thirdEmailUrl = oAuth2Bo.getThirdEmailUrl();
        final String thirdUserUrl = oAuth2Bo.getThirdUserUrl();
        if (StringUtils.hasText(thirdMobileNoUrl)) {
            final String thirdMobileNo = getThirdMobileNo(thirdMobileNoUrl, accessTokenBo);
            if (StringUtils.hasText(thirdMobileNo)) {
                oAuth2UserInfo = new OAuth2UserInfo();
                oAuth2UserInfo.setMobileNo(thirdMobileNo);
                log.info("{}{} oauth2 获取三方应用用户信息成功, oAuth2UserInfo={}", thirdPartyType, thirdPartyDesc, oAuth2UserInfo);
                return oAuth2UserInfo;
            }
        }
        if (StringUtils.hasText(thirdEmailUrl)) {
            final String thirdEmail = getThirdEmail(thirdEmailUrl, accessTokenBo);
            if (StringUtils.hasText(thirdEmail)) {
                oAuth2UserInfo = new OAuth2UserInfo();
                oAuth2UserInfo.setEmail(thirdEmail);
                log.info("{}{} oauth2 获取三方应用用户信息成功, oAuth2UserInfo={}", thirdPartyType, thirdPartyDesc, oAuth2UserInfo);
                return oAuth2UserInfo;
            }
        }
        if (StringUtils.hasText(thirdUserUrl)) {
            final String thirdUserName = getThirdUserName(thirdUserUrl, accessTokenBo);
            if (StringUtils.hasText(thirdUserName)) {
                oAuth2UserInfo = new OAuth2UserInfo();
                oAuth2UserInfo.setName(thirdUserName);
                log.info("{}{} oauth2 获取三方应用用户信息成功, oAuth2UserInfo={}", thirdPartyType, thirdPartyDesc, oAuth2UserInfo);
                return oAuth2UserInfo;
            }
        }

        log.error("{}{} oauth2 获取三方应用用户信息失败, 未获取到三方用户信息", thirdPartyType, thirdPartyDesc);
        return null;
    }

    private OAuth2BO queryOAuth2Bo(ThirdPartyEnum thirdPartyEnum) {
        final CfgThirdPartyLoginDO cfgThirdPartyLoginDo = thirdPartyComponent.queryByThirdPartyType(thirdPartyEnum.getThirdPartyType());
        final OAuth2BO oAuth2Bo = oAuth2Converter.do2Bo(cfgThirdPartyLoginDo);
        final String thirdOauthUrl = oAuth2Bo.getThirdOauthUrl();
        final String thirdMobileNoUrl = oAuth2Bo.getThirdMobileNoUrl();
        final String thirdEmailUrl = oAuth2Bo.getThirdEmailUrl();
        final String thirdUserUrl = oAuth2Bo.getThirdUserUrl();
        AssertUtil.assertTrue(StringUtils.hasText(thirdOauthUrl),
                AuthErrorCodeEnum.THIRD_PARTY_LOGIN_NOT_SUPPORT.info().newException());
        AssertUtil.assertTrue(StringUtils.hasText(thirdMobileNoUrl)
                        || StringUtils.hasText(thirdEmailUrl)
                        || StringUtils.hasText(thirdUserUrl),
                AuthErrorCodeEnum.THIRD_PARTY_LOGIN_NOT_SUPPORT.info().newException());
        return oAuth2Bo;
    }

}
